package com.xiashitech.agent.diagnosis;

import java.lang.reflect.Method;

/**
 * 间谍类<br/>
 * 藏匿在各个ClassLoader中
 */
public class Spy {


    // -- 各种Advice的钩子引用 --
    public static volatile Method ON_BEFORE_METHOD;
    public static volatile Method ON_RETURN_METHOD;
    public static volatile Method ON_THROWS_METHOD;
    public static volatile Method BEFORE_INVOKING_METHOD;
    public static volatile Method AFTER_INVOKING_METHOD;
    public static volatile Method THROW_INVOKING_METHOD;

    /*
     * 用于普通的间谍初始化
     */
    public static void init(
            Method onBeforeMethod,
            Method onReturnMethod,
            Method onThrowsMethod,
            Method beforeInvokingMethod,
            Method afterInvokingMethod,
            Method throwInvokingMethod) {
        ON_BEFORE_METHOD = onBeforeMethod;
        ON_RETURN_METHOD = onReturnMethod;
        ON_THROWS_METHOD = onThrowsMethod;
        BEFORE_INVOKING_METHOD = beforeInvokingMethod;
        AFTER_INVOKING_METHOD = afterInvokingMethod;
        THROW_INVOKING_METHOD = throwInvokingMethod;
    }

    /*
     * 用于启动线程初始化
     */
    public static void initForAgentLauncher(
            Method onBeforeMethod,
            Method onReturnMethod,
            Method onThrowsMethod,
            Method beforeInvokingMethod,
            Method afterInvokingMethod,
            Method throwInvokingMethod) {
        ON_BEFORE_METHOD = onBeforeMethod;
        ON_RETURN_METHOD = onReturnMethod;
        ON_THROWS_METHOD = onThrowsMethod;
        BEFORE_INVOKING_METHOD = beforeInvokingMethod;
        AFTER_INVOKING_METHOD = afterInvokingMethod;
        THROW_INVOKING_METHOD = throwInvokingMethod;
    }


    public static void clean() {
        ON_BEFORE_METHOD = null;
        ON_RETURN_METHOD = null;
        ON_THROWS_METHOD = null;
        BEFORE_INVOKING_METHOD = null;
        AFTER_INVOKING_METHOD = null;
        THROW_INVOKING_METHOD = null;
    }

    public static void reset(Class adviceWeaverClass) {
        if(adviceWeaverClass == null) {
            return;
        }
        try {
            ON_BEFORE_METHOD = adviceWeaverClass.getMethod("methodOnBegin",
                    int.class,
                    ClassLoader.class,
                    String.class,
                    String.class,
                    String.class,
                    Object.class,
                    Object[].class);
            ON_RETURN_METHOD = adviceWeaverClass.getMethod("methodOnReturnEnd",
                            Object.class,
                            int.class);
            ON_THROWS_METHOD = adviceWeaverClass.getMethod("methodOnThrowingEnd",
                            Throwable.class,
                            int.class);
            BEFORE_INVOKING_METHOD = adviceWeaverClass.getMethod("methodOnInvokeBeforeTracing",
                            int.class,
                            Integer.class,
                            String.class,
                            String.class,
                            String.class);
            AFTER_INVOKING_METHOD = adviceWeaverClass.getMethod("methodOnInvokeAfterTracing",
                            int.class,
                            Integer.class,
                            String.class,
                            String.class,
                            String.class);
            THROW_INVOKING_METHOD = adviceWeaverClass.getMethod("methodOnInvokeThrowTracing",
                            int.class,
                            Integer.class,
                            String.class,
                            String.class,
                            String.class,
                            String.class);
        } catch (Throwable e) {
            System.out.println(e.getMessage());
        }
    }

}
